# -*- coding: utf8 -*-

import sys
import pygame
import time
import resources
import random
from events import *
from sprites import *
from constants import *
from pygame.locals import *

class EventManager:
	def __init__(self):
		self.listeners = list()
	#---------------------------------------------------------------------------

	def registerListener(self, listener):
		self.listeners.append(listener)
	#---------------------------------------------------------------------------

	def unregisterListener(self, listener):
		self.listeners.remove(listener)
	#---------------------------------------------------------------------------

	def post(self, event):
		for listener in self.listeners:
			listener.notify(event)
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class GameView:
	def __init__(self, eventManager):
		self.eventManager = eventManager
		eventManager.registerListener(self)
		
		pygame.display.set_caption("%s - %s" % (GAME_NAME, GAME_VERSION))
		pygame.mouse.set_visible(False)
		self.window = pygame.display.set_mode((WINDOW_WIDTH * 2, WINDOW_HEIGHT * 2))
		self.buffer = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT))

		self.ship = pygame.sprite.GroupSingle()
		self.enemies = pygame.sprite.Group()
		self.enemyShots = pygame.sprite.Group()
		self.shots = pygame.sprite.Group()
		self.explosions = pygame.sprite.Group()

		self.background = Background()
		self.statusBar = StatusBar()

	#---------------------------------------------------------------------------

	def notify(self, event):
		if isinstance(event, DrawGameEvent):
			if random.randrange(1, 1000) <= 20:
				enemyNum = random.randrange(1, 4)
				if enemyNum == 1:
					Enemy1Sprite(self.eventManager, self.enemies)
				if enemyNum == 2:
					Enemy2Sprite(self.eventManager, self.enemies)
				if enemyNum == 3:
					Enemy3Sprite(self.eventManager, self.enemies)


			self.background.update()
			self.ship.update()
			self.shots.update()
			self.enemies.update()
			self.enemyShots.update()
			self.explosions.update()
			self.statusBar.update()

			for shot in self.shots:
				for enemy in self.enemies:
					if pygame.sprite.collide_rect(shot, enemy):
						shot.kill()
						enemy.kill()

			for ship in self.ship:
				for shot in self.enemyShots:
					if pygame.sprite.collide_rect(ship, shot):
						ship.kill()
						shot.kill()
						self.eventManager.post(GameOverEvent())
				for enemy in self.enemies:
					if pygame.sprite.collide_rect(ship, enemy):
						ship.kill()
						enemy.kill()
						self.eventManager.post(GameOverEvent())


			self.background.draw(self.buffer)
			self.ship.draw(self.buffer)
			self.shots.draw(self.buffer)
			self.enemies.draw(self.buffer)
			self.enemyShots.draw(self.buffer)
			self.explosions.draw(self.buffer)
			self.statusBar.draw(self.buffer)

			self.update()

		if isinstance(event, DrawTitleEvent):
			self.buffer.blit(resources.images['title'],(0,0))
			if pygame.time.get_ticks() % 700 > 300:
				rect = self.buffer.get_rect()
				self.outputText("Pressione", (rect.centerx, 200), COLOR_WHITE)
				self.outputText("Start", (rect.centerx, 215), COLOR_WHITE)
			self.update()

		if isinstance(event, DrawGameOverEvent):
			rect = self.buffer.get_rect()
			self.outputText("FIM DO JOGO", (rect.centerx, 200), COLOR_WHITE, COLOR_BLACK)
			self.update()

		if isinstance(event, ToggleFullscreenEvent):
			window = self.window
			bits = window.get_bitsize()
			flags = window.get_flags()
			flags ^= FULLSCREEN
			window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), flags, bits)

		if isinstance(event, ShootEvent):
			resources.audios['shoot'].stop()
			resources.audios['shoot'].play()
			self.shots.add(event.shoot)

		if isinstance(event, GameStartEvent):
			self.ship.empty()
			self.shots.empty()
			self.enemies.empty()
			self.enemyShots.empty()
			self.explosions.empty()
			ShipSprite(self.eventManager, self.ship)
			pygame.mixer.music.load(resources.musics['default'])
			pygame.mixer.music.play(-1, 0.0)

		if isinstance(event, GameOverEvent):
			pygame.mixer.music.stop()

		if isinstance(event, ExplosionEvent):
			resources.audios['explosion'].stop()
			resources.audios['explosion'].play()
			self.explosions.add(event.explosion)

		if isinstance(event, AddShotEvent):
			self.enemyShots.add(event.shot)
	#---------------------------------------------------------------------------
	
	def outputText(self, text, centerPosition, foregroundColor, backgroundColor=None):
		if backgroundColor:
			textSurface = resources.fonts['default'].render(text, False, foregroundColor, backgroundColor)
		else:
			textSurface = resources.fonts['default'].render(text, False, foregroundColor)
		rect = textSurface.get_rect()
		rect.centerx = centerPosition[0]
		rect.centery = centerPosition[1]
		self.buffer.blit(textSurface, rect)
	#---------------------------------------------------------------------------

	def update(self):
		pygame.transform.scale2x(self.buffer, self.window)
		pygame.display.update()
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class Title:
	def __init__(self, eventManager):
		self.eventManager = eventManager
		eventManager.registerListener(self)
	#---------------------------------------------------------------------------

	def notify(self, event):
		if isinstance(event, InputEvent):
			if event.input.start:
				self.eventManager.unregisterListener(self)
				self.eventManager.post(GameStartEvent())
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class StatusBar():
	def __init__(self):
		self.image = pygame.Surface((WINDOW_WIDTH, 10))
		self.color = COLOR_BLUE

	def draw(self, surface):
		self.image.fill(self.color)
		text = 'Pontos: %d' % (0)
		textSurface = resources.fonts['default'].render(text, False, COLOR_WHITE)
		self.image.blit(textSurface, (0,0))
		surface.blit(self.image, (0, WINDOW_HEIGHT - 10))
	def update(self):
		pass

class Background():
	def __init__(self):
		self.image = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT))
		self.rect = self.image.get_rect()
		self._background = resources.images['background']
		self._backgroundRect = self._background.get_rect()
		self.x = 0
		self.y = 0
		self.speedH = 0.4
		self.speedV = 1
	#---------------------------------------------------------------------------

	def draw(self, surface):
		self._createImage()
		surface.blit(self.image, (0,0))
	#---------------------------------------------------------------------------

	def update(self):
		self.x = self.x - self.speedH if self.x > 0 else self._backgroundRect.width
		self.y = self.y - self.speedV if self.y > 0 else self._backgroundRect.height
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

	def _createImage(self):
		self.image.fill(COLOR_BLACK)
		amountH = (self.rect.width / self._backgroundRect.width) + (self.rect.width % self._backgroundRect.width > 0) + (self.x != 0)
		amountV = (self.rect.height / self._backgroundRect.height) + (self.rect.height % self._backgroundRect.height > 0) + (self.y != 0)
		for i in xrange(amountH):
			for j in xrange(amountV):
				x = (i * self._backgroundRect.width) - self.x
				y = (j * self._backgroundRect.height) - self.y
				self.image.blit(self._background, (x, y))
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class Input:
	def __init__(self):
		self.up = False
		self.down = False
		self.left = False
		self.right = False
		self.shoot = False
		self.start = False
		self.keymap = {
			"up": K_UP,
			"down": K_DOWN,
			"left": K_LEFT,
			"right": K_RIGHT,
			"shoot": K_SPACE,
			"start": K_RETURN,
		}
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class InputController:
	def __init__(self, eventManager):
		self.eventManager = eventManager
		eventManager.registerListener(self)
		self.input = Input()
	#---------------------------------------------------------------------------
	def notify (self, event):
		if isinstance(event, TickEvent):
			self.input.shoot = False
			for event in pygame.event.get():
				ev = None
				if event.type == QUIT:
					ev = QuitEvent()
				elif event.type == KEYDOWN and event.key == K_ESCAPE:
					ev = ReturnEvent()

				if event.type == KEYDOWN and event.key == self.input.keymap['up']: self.input.up = True
				if event.type == KEYDOWN and event.key == self.input.keymap['down']: self.input.down = True
				if event.type == KEYDOWN and event.key == self.input.keymap['left']: self.input.left = True
				if event.type == KEYDOWN and event.key == self.input.keymap['right']: self.input.right = True
				if event.type == KEYDOWN and event.key == self.input.keymap['start']: self.input.start = True

				if event.type == KEYUP and event.key == self.input.keymap['up']: self.input.up = False
				if event.type == KEYUP and event.key == self.input.keymap['down']: self.input.down = False
				if event.type == KEYUP and event.key == self.input.keymap['left']: self.input.left = False
				if event.type == KEYUP and event.key == self.input.keymap['right']: self.input.right = False
				if event.type == KEYUP and event.key == self.input.keymap['start']: self.input.start = False

				if event.type == KEYDOWN and event.key == self.input.keymap['shoot']: 
					self.input.shoot = True

				if event.type == KEYDOWN and event.key == K_F11:
					self.eventManager.post(ToggleFullscreenEvent())

				if ev:
					self.eventManager.post(ev)

			self.eventManager.post(InputEvent(self.input))
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class Player:
	def __init__(self, eventManager):
		self.eventManager = eventManager
		eventManager.registerListener(self)
		self.score = 0
		self.lives = 1
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class Game:

	STATE_MENU = 1
	STATE_PLAY = 2
	STATE_GAMEOVER = 3
	STATE_PRESENTATION = 4
	STATE_QUIT = 5

	def __init__(self, eventManager):
		eventManager.registerListener(self)
		self.eventManager = eventManager
		self.fpsClock = pygame.time.Clock()
		self.eventManager.post(ShowTitleEvent())		
	#---------------------------------------------------------------------------


	def run(self):
		while True:
			if self.state == self.STATE_PRESENTATION:
				pass
			if self.state == self.STATE_MENU:
				self.eventManager.post(DrawTitleEvent())
			if self.state == self.STATE_PLAY:
				self.eventManager.post(DrawGameEvent())
			if self.state == self.STATE_GAMEOVER:
				self.eventManager.post(DrawGameOverEvent())
				pygame.time.delay(2000)
				resources.audios['gameover'].play()
				pygame.time.delay(2000)
				self.eventManager.post(ShowTitleEvent())
			if self.state == self.STATE_QUIT:
				pygame.quit()
				sys.exit()
			event = TickEvent()
			self.eventManager.post(event)
			self.fpsClock.tick(FPS)
	#---------------------------------------------------------------------------
	
	def notify(self, event):
		if isinstance(event, ReturnEvent):
			# if self.state == self.STATE_PLAY:
			# 	self.eventManager.post(ShowTitleEvent())
			# elif self.state == self.STATE_MENU:
				self.eventManager.post(QuitEvent())
		elif isinstance(event, ShowTitleEvent):
			self.state = self.STATE_MENU
			title = Title(self.eventManager)
		elif isinstance(event, GameStartEvent):
			self.state = self.STATE_PLAY
		elif isinstance(event, GameOverEvent):
			self.state = self.STATE_GAMEOVER
		elif isinstance(event, ChangeStateEvent):
			self.state = event.state
		elif isinstance(event, QuitEvent):
			pygame.quit()
			sys.exit()
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

class Main:
	def __init__(self):
		pygame.init()
		resources.loadResources()
	#---------------------------------------------------------------------------

	def run(self):
		eventManager = EventManager()
		game = Game(eventManager)
		GameView(eventManager)
		InputController(eventManager)
		game.run()
	#---------------------------------------------------------------------------
#-------------------------------------------------------------------------------

if __name__ == '__main__':
	main = Main()
	main.run()
